資料更新(Update)如同寫入或刪除一樣,都是相同 Pattern,差別是條件比較多。
db.collection.updateOne(filter, update, options)
db.collection.updateMany(filter, update, options)
兩者基本上是一樣的,相信你們看完前面的 insertOne, insertMany, deleteOne, deleteMany 都有感覺了。
filter 是過慮條件,也就是你要找到欲更新文件的條件。
options 這個是更新的設定選項,在剛開始會用不到太多項目,只有一個要特別注意,就是 upsert
,通常我們會設定為 true
,這也是 MongoDB 很方便的地方。顧名思義,就是當欲更新的文件如果存在時,進行 update
,當找不到這比文件時,就進行 insert
。
馬上來個範例,我們先查詢,確保沒有該文件,接著執行 upsert:true
的 updateOne
語法:
film> db.upsert.sample.find()
film> db.upsert.sample.updateOne({},{$set:{'name':'try upsert'}},{upsert:true})
{
acknowledged: true,
insertedId: ObjectId("6131047cf80a26301f6a5856"),
matchedCount: 0,
modifiedCount: 0,
upsertedCount: 1
}
film> db.upsert.sample.find()
[ { _id: ObjectId("6131047cf80a26301f6a5856"), name: 'try upsert' } ]
film>
可以看到 upsert.sample
collection 起初是沒有資料的,我使用了 find()
,不帶任何參數的查詢,查不到任何資料。
接著再一個 updateOne
的內容裡,執行後直接新增比資料,透過回傳的參數也可以看到 upsertedCount
數量為 1。
insertedId
:本次執行結果,寫入的 ObjectId 清單matchedCount
:本次執行結果,符合查詢條件的文件數量modifiedCount
:本次執行結果,符合查詢條件且更新的文件數量upsertedCount
:本次執行結果,進行 upsert 的文件數量接著將這次的 updateOne 語法來拆開來看:
db.upsert.sample.updateOne(
{},
{$set:{'name':'try upsert'}},
{upsert:true}
)
可以看到三組大括弧 {}
,這分別對應了上面提到的 filter
, update
與 options
。
filter
:這邊我們直接不帶條件,想進行全部文件的 updateupdate
:我們設定 name 欄位的值為 try upsert,$set 是 MongoDB 的 operator 之一,這個我們之後再講解,先忍著略過它。options
:這次 updateOne 中,設定值設定 upsert
為 true
,代表找不到資料就寫入。設定還有 writeConcern
, collation
和 hint
等,這個會在後面再講解,現在提就太深入了。這次我們準備幾筆符合查詢條件的文件,使用 UpdateOne
看看會發生什麼事情。
資料庫內有三筆名為 Arthas
的資料
film> db.upsert.demo2.find()
[
{ _id: ObjectId("61310798630faf5d23c909d3"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d6"), name: 'Thrall' }
]
執行 updateOne,將名為 Arthas
的資料欄位改為 ErrorName
film> db.upsert.demo2.updateOne({'name':'Arthas'}, {$set:{'name':'ErrorName'}})
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
film> db.upsert.demo2.find()
[
{ _id: ObjectId("61310798630faf5d23c909d3"), name: 'ErrorName' },
{ _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d6"), name: 'Thrall' }
]
可以看到執行後,再次查詢,只會有第一筆被修改,因為我們執行的是 updateOne
。
那為什麼第一筆不是_id
為9d4
或 9d5
結尾的資料呢?因為 MongoDB 採用的是 natural sort
,在這個情況下就是 9d3
這一筆。我們會在後面的天數講到 natural sort
,這是一個非重要的概念。
replaceOne,找到符合條件的文件,直接整份文件取代。
replaceOne 用法與 Update 高度相近,來看看它的長相:
db.collection.replaceOne(filter, replacement, options)
我們來嘗試找到一個文件,{name:'Thrall'}
,將它改成下面這樣子
{
'name':'NewThrall',
'type':'melee'
}
film> db.upsert.demo2.find()
[
{ _id: ObjectId("61310798630faf5d23c909d3"), name: 'ErrorName' },
{ _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d6"), name: 'Thrall' }
]
film> db.upsert.demo2.replaceOne({'name':'Thrall'}, {'name':'NewThrall', 'type':'melee'})
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
film> db.upsert.demo2.find()
[
{ _id: ObjectId("61310798630faf5d23c909d3"), name: 'ErrorName' },
{ _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
{ _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
{
_id: ObjectId("61310798630faf5d23c909d6"),
name: 'NewThrall',
type: 'melee'
}
]
可以看到新的內容已經取代上去,特別要注意的是 _id 並沒有任何異動,即便它不是客製化的 _id
,仍然不會改變,因為這個操作是取代文件內容,不會影響它本身的 key。
附帶一提,replaceOne 如同上面所說,設定值是幾乎一樣的,所以也有 upsert 功能,這邊就不再示範了,結果會與 update 一樣。
本系列文章會同步發表於我個人的部落格 Pie Note